#!/usr/bin/env node
var fs          = require('fs');
var path        = require('path');


exports.Config = ( function() {

    function Config(configFolderOrFile, rootFolder) {
    	try {
    		//try your luck and try 'requiring' it as a json file living with the source (staple ones)
        	this.config = require("./"+configFolderOrFile);
	    	this.rootFolder = configFolderOrFile; //TODO: how to get the location of the script?
    	} catch (e) {
	    	var originalGivenFolder = configFolderOrFile;
	    	if (!fs.existsSync(configFolderOrFile)) {
	    		//try with the root folder
	    		configFolderOrFile = rootFolder+"/"+configFolderOrFile;
	    		if (!fs.existsSync(configFolderOrFile)) {
	    			throw new Error("'"+originalGivenFolder+"' not found");
	    		}
	    	}

	        if (fs.statSync(configFolderOrFile).isDirectory()) {
		    	var currentFolder = configFolderOrFile;
		    	while (!fs.existsSync(configFolderOrFile = currentFolder+"/config.json")) {
		    		var folderUp = path.dirname(currentFolder);
		    		if (folderUp != currentFolder) {
		    			currentFolder = folderUp;
		    		} else {
		    			throw new Error("Could not find 'config.json' file in the given folder '"+originalGivenFolder+"' nor in any of its parents all the way to root.");
		    		}
		    	}
	        }
	    	this.config = JSON.parse(fs.readFileSync(configFolderOrFile));
	    	this.rootFolder = path.dirname(configFolderOrFile);
    	}

    	process(this, this.config, []);
    }

    Config.prototype.get = function(path) {
    	var result = this.config;
    	if (path) {
	     	for (var i = 0; i < path.length; i++) {
	    		result = result[path[i]];
	    	}
    	}
    	return result;
    }

    Config.prototype.put = function(srcNode, path, overwrite) {
    	var dstNode = this.get(path);
    	dstNode = doPut(srcNode, dstNode, overwrite);
    }

    function doPut(srcNode, dstNode, overwrite) {
    	if (overwrite) {
    		return srcNode;
    	}
    	if (typeof srcNode === "object") {
    		if (Array.isArray(srcNode)) {
    			return dstNode;
    		} else {
		    	for (var memberName in srcNode) {
		    		if (memberName in dstNode) {
		    			dstNode[memberName] = doPut(srcNode[memberName], dstNode[memberName], overwrite)
		    		} else {
		    			dstNode[memberName] = srcNode[memberName];
		    		}
		    	}
		    	return dstNode;
    		}
    	}
    }

    function process(self, node, path) {
    	if (typeof node === "object") {
    		if (Array.isArray(node)) {
    			for (var i = 0; i < node.length; i++) {
    				path.push(i);
    				process(self, node[i], path);
    				path.pop();
    			}
    		} else {
		    	for (var memberName in node) {
		    		if (memberName == "extends") {
		    			self.put(
		    				new Config(node[memberName], self.rootFolder).get(path),
		    				path,
		    				false
		    			);
		    		} else {
		    			path.push(memberName);
		    			process(self, node[memberName], path);
		    			path.pop();
		    		}
		    	}
    		}
    	}
    }

    return Config;
})();
